﻿Namespace EIB.Bus
    Public NotInheritable Class EIBBusData_FrameLData
        Inherits EIBBusData_FrameBase

        'Control Frame
        Private _Control As Byte = Nothing
        Private _RepeatFlag As BusData.EIBBusData_FrameRepeatFlag = Nothing
        Private _Priority As BusData.EIBBusData_FramePriority = Nothing
        Private _ConfirmFlag As Boolean = Nothing

        Private _SourceAddress As Addressing.EIBPhysicalAddress = Nothing
        Private _DestinationAddress As Addressing.EIBAddress = Nothing

        Private _NCPI As Byte = Nothing
        Private _DestinationType As BusData.EIBBusData_FrameDestinationType = Nothing
        Private _Routing As Byte = Nothing
        Private _DataLength As Byte = Nothing

        Private _TCPI As Byte = Nothing
        Private _ACPI As BusData.EIBBusData_FrameACPI_L_Data_Type = Nothing 'ACPI
        Private _Data As Byte() = Nothing


        ' L_Data.req 
        Sub New(priority As BusData.EIBBusData_FramePriority, destinationAddress As Addressing.EIBAddress, routing As Byte, tcpi As Byte, _
                acpi As BusData.EIBBusData_FrameACPI_L_Data_Type, data As Byte())

            MyBase.New(EIB.BusData.EIBBusData_EMICode.L_Data_req)

            If Not [Enum].IsDefined(GetType(BusData.EIBBusData_FramePriority), priority) Then Throw New ArgumentException("Priority definition not valid.", "priority")
            If destinationAddress.IsInvalid Then Throw New ArgumentException("Destination address not valid.", "destinationAddress")
            If routing > 7 Then Throw New ArgumentException("Routing count must be <= 7.", "routing")
            If Not [Enum].IsDefined(GetType(BusData.EIBBusData_FrameACPI_L_Data_Type), acpi) Then Throw New ArgumentException("")
            If data.Length < 1 Then Throw New ArgumentException("")

            _RepeatFlag = 0
            _Priority = priority
            _RepeatFlag = 0
            _Control = (_RepeatFlag << 5) + (_Priority << 2) + If(_RepeatFlag, 1, 0)

            _DestinationType = If(TypeOf destinationAddress Is Addressing.EIBPhysicalAddress, EIB.BusData.EIBBusData_FrameDestinationType.PhysicalAddress, EIB.BusData.EIBBusData_FrameDestinationType.GroupAddress)
            _Routing = routing
            _DataLength = data.Length
            _NCPI = (_DestinationType << 7) + (_Routing << 4) + _DataLength

            _SourceAddress = Addressing.EIBPhysicalAddress.Invalid
            _DestinationAddress = destinationAddress

            _TCPI = tcpi
            _ACPI = acpi
            _Data = data

            Dim busdata As Byte() = New Byte(8 + _DataLength - 1) {}
            busdata(0) = _messageCode
            busdata(1) = _Control
            busdata(2) = SourceAddress.ToByte()(0)
            busdata(3) = SourceAddress.ToByte()(1)
            busdata(4) = destinationAddress.ToByte()(0)
            busdata(5) = destinationAddress.ToByte()(1)
            busdata(6) = _NCPI
            busdata(7) = (_TCPI << 2) + ((_ACPI And &HC) >> 2)
            busdata(8) = ((_ACPI And &H3) << 6) + (data(0) And &H3F)

            For i = 1 To data.Length - 1
                busdata(8 + i) = data(i)
            Next

            _busData = busdata
        End Sub

        'L_Data.con 
        Sub New(repeatFlag As BusData.EIBBusData_FrameRepeatFlag, priority As BusData.EIBBusData_FramePriority, confirmFlag As Boolean, _
                destinationAddress As Addressing.EIBAddress, routing As Byte, tcpi As Byte, acpi As BusData.EIBBusData_FrameACPI_L_Data_Type, _
                data As Byte())

            MyBase.New(EIB.BusData.EIBBusData_EMICode.L_Data_con)

            If Not [Enum].IsDefined(GetType(EIB.BusData.EIBBusData_FrameRepeatFlag), repeatFlag) Then Throw New ArgumentException("Repeat flag definition not valid.", "repeatFlag")
            If Not [Enum].IsDefined(GetType(EIB.BusData.EIBBusData_FramePriority), priority) Then Throw New ArgumentException("Priority definition not valid.", "priority")
            If destinationAddress.IsInvalid Then Throw New ArgumentException("Destination address not valid.", "destinationAddress")
            If routing > 7 Then Throw New ArgumentException("Routing count must be <= 7.", "routing")
            If Not [Enum].IsDefined(GetType(EIB.BusData.EIBBusData_FrameACPI_L_Data_Type), acpi) Then Throw New ArgumentException("")
            If data.Length < 1 Then Throw New ArgumentException("")

            _RepeatFlag = repeatFlag
            _Priority = priority
            _ConfirmFlag = confirmFlag
            _Control = (_RepeatFlag << 5) + (_Priority << 2) + If(_RepeatFlag, 1, 0)

            _DestinationType = If(TypeOf destinationAddress Is Addressing.EIBPhysicalAddress, EIB.BusData.EIBBusData_FrameDestinationType.PhysicalAddress, EIB.BusData.EIBBusData_FrameDestinationType.GroupAddress)
            _Routing = routing
            _DataLength = data.Length
            _NCPI = (_DestinationType << 7) + (_Routing << 4) + _DataLength

            _SourceAddress = Addressing.EIBPhysicalAddress.Invalid
            _DestinationAddress = destinationAddress

            _TCPI = tcpi
            _ACPI = acpi
            _Data = data


            Dim busdata As Byte() = New Byte(8 + _DataLength - 1) {}
            busdata(0) = _messageCode
            busdata(1) = _Control
            busdata(2) = SourceAddress.ToByte()(0)
            busdata(3) = SourceAddress.ToByte()(1)
            busdata(4) = destinationAddress.ToByte()(0)
            busdata(5) = destinationAddress.ToByte()(1)
            busdata(6) = _NCPI
            busdata(7) = (_TCPI << 2) + ((_ACPI And &HC) >> 2)
            busdata(8) = ((_ACPI And &H3) << 6) + (data(0) And &H3F)

            For i = 1 To data.Length - 1
                busdata(8 + i) = data(i)
            Next

            _busData = busdata
        End Sub

        ' L_Data.ind 
        Sub New(repeatFlag As BusData.EIBBusData_FrameRepeatFlag, priority As BusData.EIBBusData_FramePriority, _
                destinationAddress As Addressing.EIBAddress, routing As Byte, tcpi As Byte, acpi As BusData.EIBBusData_FrameACPI_L_Data_Type, _
                data As Byte())

            MyBase.New(EIB.BusData.EIBBusData_EMICode.L_Data_ind)

            If Not [Enum].IsDefined(GetType(EIB.BusData.EIBBusData_FrameRepeatFlag), repeatFlag) Then Throw New ArgumentException("Repeat flag definition not valid.", "repeatFlag")
            If Not [Enum].IsDefined(GetType(EIB.BusData.EIBBusData_FramePriority), priority) Then Throw New ArgumentException("Priority definition not valid.", "priority")
            If destinationAddress.IsInvalid Then Throw New ArgumentException("Destination address not valid.", "destinationAddress")
            If routing > 7 Then Throw New ArgumentException("Routing count must be <= 7.", "routing")
            If Not [Enum].IsDefined(GetType(EIB.BusData.EIBBusData_FrameACPI_L_Data_Type), acpi) Then Throw New ArgumentException("")
            If data.Length < 1 Then Throw New ArgumentException("")

            _RepeatFlag = repeatFlag
            _Priority = priority
            _ConfirmFlag = 0
            _Control = (_RepeatFlag << 5) + (_Priority << 2) + If(_RepeatFlag, 1, 0)

            _DestinationType = If(TypeOf destinationAddress Is Addressing.EIBPhysicalAddress, EIB.BusData.EIBBusData_FrameDestinationType.PhysicalAddress, EIB.BusData.EIBBusData_FrameDestinationType.GroupAddress)
            _Routing = routing
            _DataLength = data.Length
            _NCPI = (_DestinationType << 7) + (_Routing << 4) + _DataLength

            _SourceAddress = Addressing.EIBPhysicalAddress.Invalid
            _DestinationAddress = destinationAddress

            _TCPI = tcpi
            _ACPI = acpi
            _Data = data


            Dim busdata As Byte() = New Byte(8 + _DataLength - 1) {}
            busdata(0) = _messageCode
            busdata(1) = _Control
            busdata(2) = SourceAddress.ToByte()(0)
            busdata(3) = SourceAddress.ToByte()(1)
            busdata(4) = destinationAddress.ToByte()(0)
            busdata(5) = destinationAddress.ToByte()(1)
            busdata(6) = _NCPI
            busdata(7) = (_TCPI << 2) + ((_ACPI And &HC) >> 2)
            busdata(8) = ((_ACPI And &H3) << 6) + (data(0) And &H3F)

            For i = 1 To data.Length - 1
                busdata(8 + i) = data(i)
            Next

            _busData = busdata
        End Sub

        Sub New(data As Byte())
            MyBase.New(data)

            If data.Length < 9 Then Throw New ArgumentException("Data must be at least 9 byte long for 'L_Data'.", "data")

            _Control = data(1)
            If _messageCode = EIB.BusData.EIBBusData_EMICode.L_Data_con OrElse
               _messageCode = EIB.BusData.EIBBusData_EMICode.L_Data_ind Then

                _RepeatFlag = (_Control And &H20) >> 5
            Else
                _RepeatFlag = 0
            End If
            _Priority = (_Control And &HC) >> 2
            If _messageCode = EIB.BusData.EIBBusData_EMICode.L_Data_con Then
                _ConfirmFlag = (_ConfirmFlag And &H1)
            Else
                _ConfirmFlag = 0
            End If

            _NCPI = data(6)
            _DestinationType = (_NCPI And &H80) >> 7
            _Routing = (_NCPI And &H70) >> 4
            _DataLength = (_NCPI And &HF)

            _SourceAddress = New Addressing.EIBPhysicalAddress(New Byte() {data(2), data(3)})
            _DestinationAddress = Addressing.EIBAddress.ParseAddress(New Byte() {data(4), data(5)}, _DestinationType)

            'data(6) and &HC0 muss "00" sein ?!
            _TCPI = (data(7) And &H3C) >> 2
            _ACPI = ((data(7) And &H3) << 2) + ((data(8) And &HC0) >> 6)

            If data.Length <> 8 + _DataLength Then Throw New EIB.Exceptions.EIBBusDataParseException("Data array size did not match containing data length.")

            _Data = New Byte(_DataLength - 1) {}
            _Data(0) = data(8) And &H3F
            For i = 1 To _DataLength - 1
                _Data(i) = data(8 + i)
            Next
        End Sub



        Public ReadOnly Property RepeatFlag As EIB.BusData.EIBBusData_FrameRepeatFlag
            Get
                Return _RepeatFlag
            End Get
        End Property

        Public ReadOnly Property Priority As EIB.BusData.EIBBusData_FramePriority
            Get
                Return _Priority
            End Get
        End Property

        Public ReadOnly Property ConfirmFlag As Boolean
            Get
                Return _ConfirmFlag
            End Get
        End Property

        Public ReadOnly Property SourceAddress As Addressing.EIBPhysicalAddress
            Get
                Return _SourceAddress
            End Get
        End Property

        Public ReadOnly Property DestinationAddress As Addressing.EIBAddress
            Get
                Return _DestinationAddress
            End Get
        End Property

        Public ReadOnly Property DestinationType As EIB.BusData.EIBBusData_FrameDestinationType
            Get
                Return _DestinationType
            End Get
        End Property

        Public ReadOnly Property Routing As Byte
            Get
                Return _Routing
            End Get
        End Property

        Public ReadOnly Property DataLength As Byte
            Get
                Return _DataLength
            End Get
        End Property

        Public ReadOnly Property NCPI As Byte
            Get
                Return _NCPI
            End Get
        End Property

        Public ReadOnly Property TCPI As Byte
            Get
                Return _TCPI
            End Get
        End Property

        Public ReadOnly Property ACPI As EIB.BusData.EIBBusData_FrameACPI_L_Data_Type
            Get
                Return _ACPI
            End Get
        End Property

        Public ReadOnly Property Data As Byte()
            Get
                Return _Data
            End Get
        End Property


        Public Overrides Function ToInfoList() As List(Of InfoBase)
            Dim list As New List(Of InfoBase)

            list.Add(New Info("EIB Message Code", String.Format("{0} (0x{0:X})", _messageCode)))
            Dim controlList As New List(Of InfoBase)
            list.Add(New InfoList("Control", String.Format("{0} (0x{0:X})", _Control), controlList))
            If _messageCode = EIB.BusData.EIBBusData_EMICode.L_Data_con OrElse
               _messageCode = EIB.BusData.EIBBusData_EMICode.L_Data_ind Then

                controlList.Add(New Info("Repeat Flag", String.Format("{0} (0x{0:X})", _RepeatFlag)))
            End If
            controlList.Add(New Info("Priority", String.Format("{0} (0x{0:X})", Priority)))
            If _messageCode = EIB.BusData.EIBBusData_EMICode.L_Data_con Then
                controlList.Add(New Info("Confirm Flag", String.Format("{0} (0x{0:X})", _ConfirmFlag)))
            End If
            list.Add(New Info("Source Adress", _SourceAddress.ToString()))
            list.Add(New Info("Dest. Adress", _DestinationAddress.ToString()))
            Dim ncpiList As New List(Of InfoBase)
            list.Add(New InfoList("NCPI", String.Format("{0} (0x{0:X})", _NCPI), ncpiList))
            ncpiList.Add(New Info("Dest. Type", String.Format("{0} (0x{0:X})", DestinationType)))
            ncpiList.Add(New Info("Routing", _Routing))
            ncpiList.Add(New Info("Data Length", _DataLength))
            list.Add(New Info("TCPI", String.Format("{0} (0x{0:X})", _TCPI)))
            list.Add(New Info("ACPI", String.Format("{0} (0x{0:X})", _ACPI)))
            Dim dataList As New List(Of InfoBase)
            list.Add(New InfoList("Data", "Byte[]", dataList))
            For i = 0 To _DataLength - 1
                dataList.Add(New Info(String.Format("Data {0}", i), _Data(i)))
            Next

            Return list
        End Function
    End Class
End Namespace